package com.huai.jt1078.handler;

import com.huai.jt1078.enums.DataType;
import com.huai.jt1078.utils.ByteUtil;
import com.huai.jt1078.utils.SessionManager;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @author xingkong
 * @program jt1078
 * @description 长度解析器 仅做黏包和半包处理 不进行业务逻辑处理
 * @date 2021-09-04 11:47
 **/
@Slf4j
public class LengthDecoder extends ByteToMessageDecoder {

    /**
     * byteBuf最小长度
     */
    private static final int MIN_LENGTH = 30;

    private Integer dataLength = null;
    private byte[] headerBytes = null;

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        SessionManager.instance.getContextSet().add(ctx);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int length = in.readableBytes();
        // 如果可读大小 小于最小大小 则跳过
        if (length < MIN_LENGTH && null == dataLength) {
            return;
        }
        // 如果没有设置过头信息 则设置头信息
        if (null == dataLength) {
            headerBytes = setHeader(ctx, in);
            return;
        }
        // 判断剩下的数据 如果不满足需要读取的长度 则进行读取数据
        if (in.readableBytes() < dataLength) {
            return;
        }
        ByteBuf resultBuf = ctx.alloc().buffer();
        // 尾数据
        byte[] lastBytes = new byte[dataLength];
        in.readBytes(lastBytes);
        // 创建返回结果
        resultBuf.writeBytes(headerBytes);
        resultBuf.writeBytes(lastBytes);
        out.add(resultBuf);
        // 置空两个变量
        dataLength = null;
        headerBytes = null;
    }

    /**
     * 设置头信息
     *
     * @param ctx 上下文
     * @param in  输入报文
     * @return
     */
    private byte[] setHeader(ChannelHandlerContext ctx, ByteBuf in) {
        ByteBuf outByteBuf = ctx.alloc().buffer();
        // 从头到数据类型 一共有14个字节
        int headSize = 15;
        byte[] headByte = new byte[headSize];

        in.readBytes(headByte);
        outByteBuf.writeBytes(headByte);

        // 读取 数据类型 + 分包处理标记
        byte dataTypeAndTag = in.readByte();
        outByteBuf.writeByte(dataTypeAndTag);

        // 数据类型 前四个字节0x00~0x02是视频 0x03是音频 0x04是透传
        Integer dataType = (dataTypeAndTag >> 4) & 0x0f;
        // 时间戳 8个字节
        int timeLength = 8;
        // last 字段长度
        int lastLength = 4;

        if (DataType.PASS.getType().equals(dataType)) {
            // 如果是透传 则没有时间戳和last 所以这里没有任何处理
        } else if (DataType.AUDIO.getType().equals(dataType)) {
            // 如果是音频 则没有last
            byte[] timeBytes = new byte[timeLength];
            in.readBytes(timeBytes);
            outByteBuf.writeBytes(timeBytes);
        } else {
            // 其他类型的需要读取时间戳和last
            byte[] lastBytes = new byte[lastLength + timeLength];
            in.readBytes(lastBytes);
            outByteBuf.writeBytes(lastBytes);
        }
        // 读取数据长度
        dataLength = in.readShort() & 0xffff;
        outByteBuf.writeShort(dataLength);
        return ByteUtil.readReadableBytes(outByteBuf);
    }
}
